'''
Created on 09/10/2012

@author: rcasal
'''
import datetime
from dateutil import parser
from dateutil.parser import *
from gluon.validators import IS_IN_DB, IS_LENGTH, IS_NOT_IN_DB, IS_NOT_EMPTY,\
    IS_EMPTY_OR, IS_IN_SET
from gluon.dal import Field
from domain.dal2 import DAL2
from domain.entities.usuario import Usuario
from repositories.i_repository import IRepository
from domain.entities.consulta import TipoConsulta, SubtipoConsulta, Respuesta,\
    Consulta


class TipoConsultaSubtipoConsultaRepository(IRepository):
    '''
    classdocs
    '''

    def __init__(self, sigecon, T):
        '''
        Constructor
        '''
        self.__sigecon = sigecon
        self.__table = None
        self.__T = T
        
    def define_table(self, migrate = False):
        
        self.__sigecon.define_table('SubconsultasConsultas'
        ,Field('consultasTipo', 'reference ConsultasTipo', required = True, notnull = True)
        ,Field('subconsulta', 'reference ConsultasSubTipo', required = True, notnull = True)
        ,migrate = migrate
        )
        
        self.__table = self.__sigecon['SubconsultasConsultas']
        self.add_requires()
        self.add_represents()
        
    def add_requires(self):
        self.__table.consultasTipo.requires = IS_IN_DB(self.__sigecon, self.__sigecon.ConsultasTipo.id,'%(descripcion)s')
        self.__table.subconsulta.requires = IS_IN_DB(self.__sigecon, self.__sigecon.ConsultasSubTipo.id,'%(descripcion)s')
        pass
 
    def add_represents(self):
        self.__table.consultasTipo.represent = lambda ident: self.__sigecon.ConsultasTipo(ident).descripcion if ident > 0 else ""
        self.__table.subconsulta.represent = lambda ident: self.__sigecon.ConsultasSubTipo(ident).descripcion if ident > 0 else ""
            
    def findOne(self, ident):
        raise NotImplementedError()
    
    def findAll(self):
        raise NotImplementedError()
    
    def save(self, entity):
        raise NotImplementedError()
    
    def delete(self, entity):
        raise NotImplementedError()
    
    def update(self, entity):
        raise NotImplementedError()

class TipoConsultaCondicionRepository(IRepository):
    '''
    classdocs
    '''

    def __init__(self, sigecon, T):
        '''
        Constructor
        '''
        self.__sigecon = sigecon
        self.__table = None
        self.__T = T
        
    def define_table(self, migrate = False):
        
        self.__sigecon.define_table('ConsultasConsultantes'
        ,Field('consultasTipo', 'reference ConsultasTipo', required = True, notnull = True, label = "Tipo consulta")
        ,Field('tipoConsultante', 'reference TiposConsultantes', required = True, notnull = True, label = "Tipo consultante")
        ,Field('informacion', 'string', length = 500, required = True, notnull = True, label = "Informacion")
        ,migrate = migrate
        )
        
        self.__table = self.__sigecon['ConsultasConsultantes']
        self.add_requires()
        
    def add_requires(self):
        self.__table.consultasTipo.requires = IS_IN_DB(self.__sigecon, self.__sigecon.ConsultasTipo.id,'%(descripcion)s')
        self.__table.tipoConsultante.requires = IS_IN_DB(self.__sigecon, self.__sigecon.TiposConsultantes.id,'%(descripcion)s')
        self.__table.informacion.requires = IS_NOT_EMPTY()
 
    def add_represents(self):
        self.__table.consultasTipo.represent = lambda ident: self.__sigecon.ConsultasTipo(id).descripcion if ident > 0 else "vacio"
        self.__table.tipoConsultante.represent = lambda ident: self.__sigecon.TiposConsultantes(id).descripcion if ident > 0 else "vacio"
         
            
    def findOne(self, ident):
        raise NotImplementedError()
    
    def findAll(self):
        raise NotImplementedError()
    
    def save(self, entity):
        raise NotImplementedError()
    
    def delete(self, entity):
        raise NotImplementedError()
    
    def update(self, entity):
        raise NotImplementedError()

class TipoConsultaRepository(IRepository):
    '''
    classdocs
    '''

    def __init__(self, sigecon, T):
        '''
        Constructor
        '''
        self.__sigecon = sigecon
        self.__table = None
        self.__T = T
        
    def define_table(self, migrate = False):
        
        self.__sigecon.define_table('ConsultasTipo'
        ,Field('descripcion', 'string', length = 250, unique = True, required = True, notnull = True)
        ,migrate = migrate
        )
        self.__table = self.__sigecon['ConsultasTipo']
        self.add_requires()
        
    def add_requires(self):
        self.__table.descripcion.requires = [IS_NOT_IN_DB(self.__sigecon, self.__sigecon.ConsultasTipo.descripcion), IS_NOT_EMPTY()]
           
    def add_represents(self):
        raise NotImplementedError()     
     
    def findOne(self, ident):
        fields =  self.__sigecon(self.__sigecon.ConsultasTipo.id == ident).select().last() 
        if fields:
            return TipoConsulta.deserialize(fields)
        else:
            return None  
    
    def findAll(self):
        res = self.__sigecon(self.__sigecon.ConsultasTipo.id > 0).select(orderby = 'ConsultasTipo.descripcion ASC') 
        tipos = []
        for fields in res:
            tipos.append(TipoConsulta.deserialize(fields))
        return tipos
    
    def save(self, entity):
        raise NotImplementedError()
    
    def delete(self, entity):
        raise NotImplementedError()
    
    def update(self, entity):
        raise NotImplementedError()
    
    def findByCondicionConsultante(self, idCondicion):
        result =  self.__sigecon((self.__sigecon.ConsultasConsultantes.tipoConsultante == idCondicion) & (self.__sigecon.ConsultasTipo.id == self.__sigecon.ConsultasConsultantes.consultasTipo)).select(self.__sigecon.ConsultasTipo.id, self.__sigecon.ConsultasTipo.descripcion)
        tipos = []
        for res in result:
            tipoconsulta = TipoConsulta()
            tipoconsulta.ID = res.id
            tipoconsulta.descripcion = res.descripcion
            tipos.append(tipoconsulta)
        return tipos
                
class SubtipoConsultaRepository(IRepository):
    '''
    classdocs
    '''

    def __init__(self, sigecon, T):
        '''
        Constructor
        '''
        self.__sigecon = sigecon
        self.__table = None
        self.__T = T
        
    def define_table(self, migrate = False):
        
        self.__sigecon.define_table('ConsultasSubTipo'
        ,Field('descripcion', 'string', length = 250, unique = True, required = True, notnull = True)
        ,migrate = migrate
        )
        self.__table = self.__sigecon['ConsultasSubTipo']
        self.add_requires()
        
    def add_requires(self):
        self.__table.descripcion.requires = [IS_NOT_IN_DB(self.__sigecon, self.__sigecon.ConsultasSubTipo.descripcion), IS_NOT_EMPTY()]
         
    def add_represents(self):
        IRepository.add_represents(self)
           
    def findOne(self, ident):
        fields =  self.__sigecon(self.__sigecon.ConsultasSubTipo.id == ident).select().last() 
        if fields:
            return SubtipoConsulta.deserialize(fields)
        else:
            return None  
    
    def findAll(self):
        res = self.__sigecon(self.__sigecon.ConsultasSubTipo.id > 0).select(orderby = 'ConsultasSubTipo.descripcion ASC') 
        tipos = []
        for fields in res:
            tipos.append(SubtipoConsulta.deserialize(fields))
        return tipos
    
    def save(self, entity):
        raise NotImplementedError()
    
    def delete(self, entity):
        raise NotImplementedError()
    
    def update(self, entity):
        raise NotImplementedError()
    
    def findBytipoConsulta(self, idConsulta):
        result =  self.__sigecon((self.__sigecon.SubconsultasConsultas.consultasTipo == idConsulta) & (self.__sigecon.ConsultasSubTipo.id == self.__sigecon.SubconsultasConsultas.subconsulta)).select(self.__sigecon.ConsultasSubTipo.id, self.__sigecon.ConsultasSubTipo.descripcion)
        subtipos = []
        for res in result:
            subtipoconsulta = SubtipoConsulta()
            subtipoconsulta.ID = res.id
            subtipoconsulta.descripcion = res.descripcion
            subtipos.append(subtipoconsulta)
        return subtipos
    
class RespuestaRepository(IRepository):
    '''
    classdocs
    '''

    def __init__(self, sigecon, T):
        '''
        Constructor
        '''
        self.__sigecon = sigecon
        self.__table = None
        self.__T = T
        
    def define_table(self, migrate = False):
        
        self.__sigecon.define_table('RespuestasTipo'
        ,Field('descripcion', 'string', length = 250, unique = True, required = True, notnull = True)
        ,Field('codigo', type = 'string', length = 10, unique = True, required = True, notnull = True)
        ,migrate = migrate
        )
        self.__table = self.__sigecon['RespuestasTipo']
        self.add_requires()
        
    def add_requires(self):
        self.__table.descripcion.requires = [IS_NOT_IN_DB(self.__sigecon, self.__sigecon.RespuestasTipo.descripcion), IS_NOT_EMPTY()]
        self.__table.codigo.requires = [IS_NOT_IN_DB(self.__sigecon, self.__sigecon.RespuestasTipo.codigo), IS_NOT_EMPTY()]
             
    def add_represents(self):
        IRepository.add_represents(self)        
    
    def findOne(self, ident):
        fields =  self.__sigecon(self.__sigecon.RespuestasTipo.id == ident).select().last() 
        if fields:
            return Respuesta.deserialize(fields)
        else:
            return None  
    
    def findAll(self):
        res = self.__sigecon(self.__sigecon.RespuestasTipo.id > 0).select(orderby = 'RespuestasTipo.id ASC') 
        respuestas = []
        for fields in res:
            respuestas.append(Respuesta.deserialize(fields))
        return respuestas
    
    
    def save(self, entity):
        raise NotImplementedError()
    
    def delete(self, entity):
        raise NotImplementedError()
    
    def update(self, entity):
        raise NotImplementedError()
    
class ConsultaRepository(IRepository):
    '''
    classdocs
    '''
    
    @property
    def tabla(self):
        return self.__table
    
    def __init__(self, sigecon, auth, T):
        '''
        Constructor
        '''
        self.__sigecon = sigecon
        self.__auth = auth
        self.__table = None
        self.__T = T
        
    def define_table(self, migrate = False):
        self.__sigecon.define_table('Consultas',              
        Field('comunicacion', type = 'reference Comunicaciones', notnull = True, writable = False, readable = False, required = True),
        Field('consulta', type = 'reference ConsultasTipo', required = True, notnull = True,label = 'Consulta'),
        Field('subconsulta', type = 'reference ConsultasSubTipo', required = True, notnull = True,label = 'Subconsulta'),
        Field('respuesta', type = 'reference RespuestasTipo', required = True, notnull = True,label = 'Respuesta'),
        Field('comentarios', type = 'text', required = True, notnull = True,label = 'Comentario'),         
        Field('sector', type = 'reference Sectores', ondelete = "NO ACTION", required = False, notnull = False, label = 'Sector derivado'),
        Field('finalizado', type = 'boolean', length = 1, writable = False, readable = False, required = True, notnull = True),
        Field('creado_en', type = 'datetime', default = datetime.datetime.now(), update = datetime.datetime.now(), writable = False, readable = False, notnull = True),
        Field('usuario', type = 'reference auth_user', ondelete="NO ACTION", default = self.__auth.user_id, writable = False, readable = False, required = True, notnull = True),
        migrate = migrate
        )
        self.__table = self.__sigecon['Consultas']
        self.add_requires()
        
    def tableResolucionPendientes(self, consulta):
        tabla = DAL2(None).define_table('Pendiente',              
        Field('respuesta', type = 'integer', required = True, notnull = True,label = 'Respuesta'),
        Field('comentarios', type = 'text', required = True, notnull = True,label = 'Comentario'),         
        Field('sector', type = 'integer', required = False, notnull = False, label = 'Sector derivado'),
        )
        
        tabla.respuesta.requires = IS_EMPTY_OR(IS_IN_SET([], zero = self.__T('choose one')))
        tabla.sector.requires = IS_EMPTY_OR(IS_IN_SET([], zero = self.__T('choose one')))
        tabla.comentarios.requires = IS_LENGTH(500, 10)
        
        if consulta.subtipo != None:
            tabla.respuesta.requires = IS_IN_DB(self.__sigecon(self.__sigecon.RespuestasTipo.id > 0), 'RespuestasTipo.id', '%(descripcion)s', orderby = 'RespuestasTipo.id ASC', zero = self.__T('choose one')) 
            if consulta.comunicacion.modalidad.descripcion == "MAIL":
                tabla.respuesta.requires = IS_IN_DB(self.__sigecon(self.__sigecon.RespuestasTipo.id == 1), 'RespuestasTipo.id', '%(descripcion)s', orderby = 'RespuestasTipo.id ASC', zero = self.__T('choose one')) 

            
        if consulta.respuesta != None and consulta.respuesta.codigo == "DERIVADA":
            tabla.sector.requires = IS_IN_DB(self.__sigecon(self.__sigecon.Sectores.admite_derivacion == True), 'Sectores.id', '%(descripcion)s', orderby = 'Sectores.descripcion ASC', zero = self.__T('choose one'))
       
        return tabla
        
    def add_requires(self):
        self.__table.consulta.requires = IS_EMPTY_OR(IS_IN_SET([], zero = self.__T('choose one')))
        self.__table.subconsulta.requires = IS_EMPTY_OR(IS_IN_SET([], zero = self.__T('choose one')))
        self.__table.respuesta.requires = IS_EMPTY_OR(IS_IN_SET([], zero = self.__T('choose one')))
        self.__table.sector.requires = IS_EMPTY_OR(IS_IN_SET([], zero = self.__T('choose one')))
        self.__table.comentarios.requires = IS_LENGTH(500, 10)
        
#        self.__table.consulta.requires = IS_IN_DB(self.__sigecon, self.__sigecon.ConsultasTipo.id, '%(descripcion)s', orderby = 'ConsultasTipo.descripcion ASC', zero = self.__T('choose one'))
#        self.__table.subconsulta.requires = IS_IN_DB(self.__sigecon, self.__sigecon.ConsultasSubTipo.id, '%(descripcion)s', orderby = 'ConsultasSubTipo.descripcion ASC', zero = self.__T('choose one'))
#        self.__table.respuesta.requires = IS_IN_DB(self.__sigecon, self.__sigecon.RespuestasTipo.id, '%(descripcion)s', orderby = 'RespuestasTipo.descripcion ASC', zero = self.__T('choose one'))
#        self.__table.sector.requires = IS_IN_DB(self.__sigecon, self.__sigecon.Sectores.id, '%(descripcion)s', orderby = 'Sectores.descripcion ASC', zero = self.__T('choose one'))
#        self.__table.comentarios.requires = IS_LENGTH(500, 10)
            
            
    def add_represents(self):
        self.__table.consulta.represent = lambda ident: self.__sigecon.ConsultasTipo(ident).descripcion if ident > 0 else "sin datos"
        self.__table.subconsulta.represent = lambda ident: self.__sigecon.ConsultasSubTipo(ident).descripcion if ident > 0 else "sin datos"
        self.__table.respuesta.represent = lambda ident: self.__sigecon.RespuestasTipo(ident).descripcion if ident > 0 else "sin datos"
        self.__table.sector.represent = lambda ident: self.__sigecon.Sectores(ident).descripcion if ident > 0 else "sin derivar"
        self.__table.finalizado.represent = lambda valor: "SI" if valor == 1 else "NO"
        self.__table.comentarios.represent = lambda valor: valor if valor != "" else "sin datos" 

    def refresh_requires(self, consulta):
        if consulta.comunicacion:
        
            if consulta.comunicacion.condicion != None:
                idcondicion = consulta.comunicacion.condicion.ID
                self.__table.consulta.requires = IS_IN_DB(self.__sigecon((self.__sigecon.ConsultasConsultantes.tipoConsultante == idcondicion) & (self.__sigecon.ConsultasTipo.id == self.__sigecon.ConsultasConsultantes.consultasTipo)), 'ConsultasTipo.id', '%(descripcion)s', orderby = 'ConsultasTipo.descripcion ASC', zero = self.__T('choose one'))        
            
            if consulta.tipo != None:
                self.__table.subconsulta.requires = IS_IN_DB(self.__sigecon((self.__sigecon.SubconsultasConsultas.consultasTipo == consulta.tipo.ID) & (self.__sigecon.SubconsultasConsultas.subconsulta == self.__sigecon.ConsultasSubTipo.id)), 'ConsultasSubTipo.id', '%(descripcion)s', orderby = 'ConsultasSubTipo.descripcion ASC', zero = self.__T('choose one')) 

            if consulta.subtipo != None:
                self.__table.respuesta.requires = IS_IN_DB(self.__sigecon(self.__sigecon.RespuestasTipo.id > 0), 'RespuestasTipo.id', '%(descripcion)s', orderby = 'RespuestasTipo.id ASC', zero = self.__T('choose one')) 
                if consulta.comunicacion.modalidad.descripcion == "MAIL":
                    self.__table.respuesta.requires = IS_IN_DB(self.__sigecon(self.__sigecon.RespuestasTipo.id == 1), 'RespuestasTipo.id', '%(descripcion)s', orderby = 'RespuestasTipo.id ASC', zero = self.__T('choose one')) 

            if consulta.respuesta != None and consulta.respuesta.codigo == "DERIVADA":
                usuario = self.__auth.get_user()
                idSector = usuario.sector.ID
                self.__table.sector.requires = IS_IN_DB(self.__sigecon((self.__sigecon.Sectores.admite_derivacion == True) & (self.__sigecon.Sectores.id != idSector)), 'Sectores.id', '%(descripcion)s', orderby = 'Sectores.descripcion ASC', zero = self.__T('choose one'))


    def save(self, fields):
        return self.__table.insert(**self.__table._filter_fields(fields))
    
    def delete(self):
        raise NotImplementedError()
    
    def update(self, entity = None, fields = None):
        if entity:
            record = self.__sigecon(self.__sigecon.Consultas.id == entity.ID).select().first()
            sector = None
            if entity.sector:
                sector = entity.sector.ID
            record.update_record(
                    comunicacion = entity.comunicacion.ID,
                    consulta = entity.tipo.ID,
                    subconsulta = entity.subtipo.ID,
                    respuesta = entity.respuesta.ID,
                    comentarios = entity.comentario,
                    sector = sector,
                    usuario = entity.usuario.ID,
                    finalizado = entity.finalizado
            )
        else:
            raise NotImplementedError()    
    
    
    def getFieldsJoins(self):
        q = (self.__sigecon.Consultas.id > 0) 
        q = (q) & (self.__sigecon.Consultas.consulta == self.__sigecon.ConsultasTipo.id)
        q = (q) & (self.__sigecon.Consultas.subconsulta == self.__sigecon.ConsultasSubTipo.id)
        q = (q) & (self.__sigecon.Consultas.respuesta == self.__sigecon.RespuestasTipo.id)
        q = (q) & (self.__sigecon.Consultas.comunicacion == self.__sigecon.Comunicaciones.id)
        q = (q) & (self.__sigecon.Comunicaciones.usuario == self.__sigecon.auth_user.id)
        return q
    
    def findOne(self, ident, asdict = False):
        fields =  self.__sigecon(self.__sigecon.Consultas.id == ident).select().last() 
        if asdict == True:
            return fields
        if fields:
            return Consulta.deserialize(fields)
        return None
    
    def findAll(self, asdict = False):
        resultado =self.__sigecon(self.__sigecon.Consultas.id > 0).select(orderby = 'Consultas.id ASC')  
        if asdict == True:
            return resultado
        else:
            consultas = []
            for fields in resultado:
                consultas.append(Consulta.deserialize(fields))
                return consultas
            
    def findByDate(self, fechaDesde, fechaHasta = None, asdict = True): 
        pfechaDesde = parse("00:00:00", default=fechaDesde)
        if(fechaHasta == None):
            pfechaHasta = parse("23:59:59", default=fechaDesde)   
        else:
            pfechaHasta = parse("23:59:59", default=fechaHasta)
            
        resultado =self.__sigecon((self.__sigecon.Consultas.creado_en >= pfechaDesde) & (self.__sigecon.Consultas.creado_en <= pfechaHasta)).select(orderby = 'Consultas.id ASC')  
        if asdict == True:
            return resultado
        consultas = []
        for fields in resultado:
            consultas.append(Consulta.deserialize(fields))
            return consultas
    
    
    def findAllByIdComunicacion(self, comunicacion, asdict = False):
        resultado =  self.__sigecon(self.__sigecon.Consultas.comunicacion == comunicacion).select(orderby = 'Consultas.id DESC') 
        if asdict == True:
            return resultado
        consultas = []
        for fields in resultado:
            consultas.append(Consulta.deserialize(fields))
        return consultas
    
    
    def findByFinalizado(self, finalizado, asdict = False):
        resultado =  self.__sigecon(self.__sigecon.Consultas.finalizado == finalizado).select(orderby = 'self.__sigecon.Consultas.id DESC')
        if asdict == True:
            return resultado
        consultas = []
        for fields in resultado:
            consultas.append(Consulta.deserialize(fields))
        return consultas
    
    def findByUser(self, usuario, asdict = False):
        user = Usuario
        user = usuario
        resultado =  self.__sigecon(self.__sigecon.Consultas.usuario == user.ID).select(orderby = 'self.__sigecon.Consultas.id DESC')
        if asdict == True:
            return resultado
        consultas = []
        for fields in resultado:
            consultas.append(Consulta.deserialize(fields))
        return consultas


     
class MotivoModificacionRepository(IRepository):
    '''
    classdocs
    '''
    @property
    def tabla(self):
        return self.__table
    
    def __init__(self, sigecon, T):
        '''
        Constructor
        '''
        self.__sigecon = sigecon
        self.__table = None
        self.__T = T
        
    def define_table(self, migrate = False):
        self.__sigecon.define_table('MotivosModificacion',              
        Field('descripcion', type = 'string', length = 50, notnull = True, required = True),
        Field('codigo', type = 'string', length = 15, required = True, notnull = True),
        migrate = migrate
        )
        self.__table = self.__sigecon['MotivosModificacion']
        
    def add_requires(self):
        raise NotImplementedError()
          
    def add_represents(self):
        raise NotImplementedError()
    
    def refresh_requires(self):
        raise NotImplementedError()
    
    def findOne(self, ident):
        raise NotImplementedError()
    
    def findAll(self):
        raise NotImplementedError()
    
    def save(self, entity):
        raise NotImplementedError()
    
    def delete(self, entity):
        raise NotImplementedError()
    
    def update(self, entity):
        raise NotImplementedError()
    
        
class ConsultaHistoryRepository(IRepository):
    '''
    classdocs
    '''
    
    @property
    def tabla(self):
        return self.__table
    
    def __init__(self, sigecon,T):
        '''
        Constructor
        '''
        self.__sigecon = sigecon
        self.__table = None
        self.__T = T
        
    def define_table(self, migrate = False):
        self.__sigecon.define_table('Consultas_archive',              
        Field('current_record', 'reference Consultas', ondelete = "NO ACTION" , notnull = True),
        self.__sigecon.Consultas,
        migrate = migrate
        )
        self.__table = self.__sigecon['Consultas_archive']
        
    def add_requires(self):
        raise NotImplementedError()
            
    def add_represents(self):
        raise NotImplementedError()
    
    def refresh_requires(self):
        raise NotImplementedError()
      
    def findOne(self, ident):
        raise NotImplementedError()
    
    def findAll(self):
        raise NotImplementedError()
    
    def findAllByIdConsulta(self, consulta, asdict = False):
        resultado =  self.__sigecon(self.__sigecon.Consultas_archive.current_record == consulta).select() 
        if asdict == True:
            return resultado
        raise NotImplementedError()
    
    def save(self, entity = None, fields = None):
        if entity:
            sector = None
            if entity.sector:
                sector = entity.sector.ID
            self.__sigecon.Consultas_archive.insert(
                    current_record = entity.referencia,
                    comunicacion = entity.comunicacion.ID,
                    consulta = entity.tipo.ID,
                    subconsulta = entity.subtipo.ID,
                    respuesta = entity.respuesta.ID,
                    comentarios = entity.comentario,
                    sector = sector,
                    finalizado = entity.finalizado,
                    usuario = entity.usuario,
                    creado_en = entity.fecha
            )
        else:
            raise NotImplementedError()
            
    
    def delete(self, entity):
        raise NotImplementedError()
    
    def update(self, entity):
        raise NotImplementedError()
    